//
//  bloom_filter.h
//  9.24_bloom_filter
//
//  Created by Shi HaoRan on 2023/9/24.
//

#pragma once

#include "bit_set.h"
#include <string>

using namespace std;

namespace shr
{
    struct BKDRHash
    {
        size_t operator()(const string& str)
        {
            size_t hash = 0;
            for(auto& ch : str)
            {
              hash = hash * 131 + ch;
            }
            return hash;
        }
    };

    struct APHash
    {
        size_t operator()(const string& str)
        {
          size_t hash = 0;
          for(size_t i = 0; i < str.size(); ++i)
          {
            char ch = str[i];
            if(ch & 1)
            {
                hash ^= (~((hash << 11) ^ (str[i++]) ^ (hash >> 5)));
            }
            else 
            {
                hash ^= ((hash << 7) ^ (str[i++]) ^ (hash >> 3));
            }
          }
          return hash;
        }
    };

    struct DJBHash
    {
      size_t operator()(const string& str)
      {
          size_t hash = 0;
          for(size_t i = 0; i < str.size(); ++i)
          {
            hash += (hash << 5) + (str[i++]);
          }
          return (hash & 0x7FFFFFFF);
      }
    };

    template<size_t N, class hash1 = BKDRHash, 
      class hash2 = APHash, class hash3 = DJBHash>
    class bloom_filter
    {
    private:
        typedef bloom_filter<N> Self;
        
    public:
        Self& set(const string& str)
        {
          // size_t h1 = hash1()(str); 
          // size_t h2 = hash2()(str);
          // size_t h3 = hash3()(str);
           _bitSet.set((hash1()(str)) % N);
           _bitSet.set((hash2()(str)) % N);
           _bitSet.set((hash3()(str)) % N);
        }
        
        bool test(const string& str)
        {
            return _bitSet.test(hash1()(str) % N) && 
              _bitSet.test(hash2()(str) % N) &&
              _bitSet.test(hash3()(str) % N);
        }
        
    private:
        shr::bit_set<N> _bitSet;
    };
}
